/*
* Copyright (c)  2017, ueboot.com
* All rights reserved.
* 2017-10-29 11:39:14
*/
package com.ueboot.weishop.service.order.impl;

import com.ueboot.core.repository.BaseRepository;
import com.ueboot.core.service.impl.BaseServiceImpl;
import com.ueboot.core.utils.DateUtils;
import com.ueboot.core.utils.NumberUtil;
import com.ueboot.weishop.entity.customer.CustomerInfoEntity;
import com.ueboot.weishop.entity.order.*;
import com.ueboot.weishop.repository.order.OrderIssueRepository;
import com.ueboot.weishop.repository.order.OrderRepository;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.customer.CustomerInvoiceService;
import com.ueboot.weishop.service.customer.CustomerReceiverService;
import com.ueboot.weishop.service.customer.CustomerService;
import com.ueboot.weishop.service.order.*;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by yangkui  on 2017-10-29 11:39:14.
 *
 * @author yangkui
 * @since 2.0 by autocode
 */
@Slf4j
@Service
public class OrderServiceImpl extends BaseServiceImpl<OrderEntity> implements OrderService {
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private OrderItemService orderItemService;


    @Autowired
    private OrderExtensionService orderExtensionService;

    @Autowired
    private OrderIssueRepository orderIssueRepository;

    @Autowired
    private CacheService cacheService;
    @Autowired
    private CustomerService customerService;

    @Autowired
    private OrderReceiverService orderReceiverService;
    @Autowired
    private OrderInvoiceService orderInvoiceService;

    @Override
    protected BaseRepository getBaseRepository() {
        return orderRepository;
    }

    /**
     * 初始化下订单，状态为未支付
     *
     * @param order     订单
     * @param orderItem 订单明细
     */
    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
    public void saveOrder(OrderEntity order, OrderItemEntity orderItem, OrderExtensionEntity extensionEntity,
                          OrderInvoiceEntity orderInvoiceEntity, OrderReceiverEntity orderReceiverEntity) {
        //查询customer对象是否存在
        CustomerInfoEntity customer = customerService.findByOpenId(order.getCustomerOpenId());
        if (customer == null) {
            customer = new CustomerInfoEntity();
            customer.setOpenId(order.getCustomerOpenId());
            this.customerService.save(customer);
        }
        order.setCustomer(customer);
        if(this.findByOrderNo(order.getOrderNo())!=null){
            log.info("已经存在重复订单号，不保存！orderNo:{}",order.getOrderNo());
            return;
        }
        this.save(order);
        this.orderItemService.save(orderItem);
        this.orderExtensionService.save(extensionEntity);
        if (orderInvoiceEntity != null) {
            orderInvoiceEntity.setCustomer(customer);
            this.orderInvoiceService.save(orderInvoiceEntity);
        }

        if (orderReceiverEntity != null) {
            orderReceiverEntity.setCustomer(customer);
            this.orderReceiverService.save(orderReceiverEntity);
        }

    }

    /**
     * 修改订单状态
     *
     * @param orderNo     订单号
     * @param orderStatus 订单状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
    public OrderEntity updateOrderStatus(String orderNo, String orderStatus) {
        log.info("修改订单状态，订单号:{},订单状态:{}", orderNo, orderStatus);
        OrderEntity orderEntity = this.findByOrderNo(orderNo);
        Assert.notNull(orderEntity);
        if (OrderEnum.ORDER_STATUS_2.equals(orderEntity.getOrderStatus())) {
            log.info("订单已经支付成功，无法修改为:{}", orderStatus);
        } else {
            orderEntity.setOrderStatus(orderStatus);
            this.save(orderEntity);
            // 更新缓存
            cacheService.updateOrderStatus(orderEntity.getActivitySN(), orderEntity);
        }
        // 更新缓存
        return orderEntity;
    }

    /**
     * 支付成功后的订单状态更新
     *
     * @param orderNo       订单号
     * @param transactionId 微信平台交易号
     * @return 更新后的订单对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
    public OrderEntity updateOrderStatusAndPayNotice(String orderNo, String transactionId) {
        OrderEntity order = this.updateOrderStatus(orderNo, OrderEnum.ORDER_STATUS_2);
        Date now = new Date();
        order.setTransactionNo(transactionId);
        order.setExtStatus(OrderEnum.EXT_STATUS_0);
        order.setPayTime(now);
        order.setApplyRefundValidTime(DateUtils.getNextDay(now, 7));
        this.save(order);
        // 更新缓存
        cacheService.updateOrderStatus(order.getActivitySN(), order);
        return order;
    }

    /**
     * 根据订单号查询订单
     *
     * @param orderNo 订单号
     * @return
     */
    @Override
    public OrderEntity findByOrderNo(String orderNo) {
        return orderRepository.findByOrderNo(orderNo);
    }

    @Override
    @Cacheable(key = "'weishop:orders:'+#orderNo+'", cacheNames = "orders")
    public Integer findGoodsCountByOrderNo(String orderNo) {
        OrderEntity e = orderRepository.findByOrderNo(orderNo);
        return  e.getGoodsCount();
    }

    @Override
    public OrderEntity findBykeyForLimit(String keyForLimit) {
        return orderRepository.findBykeyForLimit(keyForLimit);
    }

    @Override
    public Page<OrderEntity> findByReq(Pageable pageable, OrderEntity params,Date startTime, Date endTime,String keyWord) {
        OrderEntity entity = new OrderEntity();
        entity.setRefundStatus(null);
        entity.setOrderStatus(null);
        ExampleMatcher example = ExampleMatcher.matching().withIgnoreNullValues()
                .withIgnorePaths("goodsCount", "originalPrice", "payAmount", "agreeRule", "needInvoice");
        if(StringUtil.isNotBlank(keyWord)){
            entity.setGoodsName(keyWord);
            example.withMatcher("goodsName",matcher -> matcher.contains());
        }
        if (StringUtil.isNotBlank(params.getKeyForLimit())) {
            entity.setKeyForLimit(params.getKeyForLimit());
            example.withMatcher("keyForLimit", matcher -> matcher.exact());
        }
        if (StringUtil.isNotBlank(params.getOrderNo())) {
            entity.setOrderNo(params.getOrderNo());
            example.withMatcher("orderNo", matcher -> matcher.exact());
        }
        if (StringUtil.isNotBlank(params.getOrderStatus())) {
            entity.setOrderStatus(params.getOrderStatus());
            example.withMatcher("orderStatus", matcher -> matcher.exact());
        }
        if (StringUtil.isNotBlank(params.getRefundStatus())) {
            entity.setRefundStatus(params.getRefundStatus());
            example.withMatcher("refundStatus", matcher -> matcher.exact());
        }

        Page<OrderEntity> pages=null;
        if(null!=startTime&&null!=endTime) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startTimeStr = sdf.format(startTime);
            String endTimeStr = sdf.format(endTime);
            List<OrderEntity> listOld=null;
                listOld=orderRepository.findAllOrderEntityByTime(startTimeStr,endTimeStr);
            List<OrderEntity> list=new ArrayList<OrderEntity>();
            for(OrderEntity oie:listOld){
                Boolean addFlag=true;
                if (StringUtil.isNotBlank(params.getKeyForLimit())) {
                    if(StringUtils.isNotBlank(oie.getKeyForLimit())&&!oie.getKeyForLimit().equals(params.getKeyForLimit())){
                        addFlag=false;
                    }
                }
                if (StringUtil.isNotBlank(params.getOrderNo())) {
                    if(StringUtils.isNotBlank(oie.getOrderNo())&&!oie.getOrderNo().equals(params.getOrderNo())){
                        addFlag=false;
                    }
                }
                if (StringUtil.isNotBlank(params.getOrderStatus())) {
                    if(StringUtils.isNotBlank(oie.getOrderStatus())&&!oie.getOrderStatus().equals(params.getOrderStatus())){
                        addFlag=false;
                    }
                }
                if (StringUtil.isNotBlank(params.getRefundStatus())) {
                    if(StringUtils.isNotBlank(oie.getRefundStatus())&&!oie.getRefundStatus().equals(params.getRefundStatus())){
                        addFlag=false;
                    }
                }
                if(addFlag){
                    list.add(oie);}
            }

            Integer total=list.size();
            Integer pageSize = pageable.getPageSize();
            Integer pageNo = pageable.getPageNumber();
            Integer startIndex = pageSize * pageNo;
            list=list.subList(startIndex,(startIndex+10)<total?startIndex+10:total);
            pages=new PageImpl<OrderEntity>(list,pageable,total);
        }
        else{
            pages=orderRepository.findAll(Example.of(entity, example), pageable);
        }
        return pages;
    }

    @Override
    public List<OrderEntity> findByCustomerId(Long customerId) {
        return orderRepository.findByCustomerId(customerId);
    }

    @Override
    public Page<OrderEntity> findByCustomerId(Pageable pageable, Long customerId) {
        return orderRepository.findByCustomerId(pageable, customerId);
    }

    @Override
    public Page<OrderEntity> findByCustomerIdAndOrderStatusAndRefundStatus(Pageable pageable, Long customerId, String orderStatus, String refundStatus) {
        return orderRepository.findByCustomerIdAndOrderStatusAndRefundStatus(pageable, customerId, orderStatus, refundStatus);
    }

    @Override
    public Page<OrderEntity> findByCustomerIdAndRefundStatusNot(Pageable pageable, Long customerId, String refundStatus) {
        return orderRepository.findByCustomerIdAndRefundStatusNot(pageable, customerId, refundStatus);
    }

    @Override
    public List<OrderEntity> findByExtStatusAndOrderStatus(Integer extStatus, String orderStatus) {
        return orderRepository.findByExtStatusAndOrderStatus(extStatus, orderStatus);
    }

    @Override
    public String getOrderNo() {
        BigDecimal bigDecimal = orderRepository.getOrderNo();
        String orderNo = "WS" + NumberUtil.getOrderNo(bigDecimal.longValue());
        return orderNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
    public Integer updateExtStatusByExtStatusAndOrderStatusAndCategory(Integer extStatusNow, Integer extStatusOld, String orderStatus, String category1, String category2) {
        return orderRepository.updateExtStatusByExtStatusAndOrderStatusAndCategory(extStatusNow, extStatusOld, orderStatus, category1, category2);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
    public void update(OrderEntity order) {
        orderRepository.save(order);
    }
}
